package com.information.manage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.information.manage.basic.common.result.Result;
import com.information.manage.basic.common.token.TokenUtils;
import com.information.manage.basic.common.utils.ConvertUtils;
import com.information.manage.basic.common.utils.FileUtils;
import com.information.manage.basic.common.utils.PathUtils;
import com.information.manage.basic.common.utils.UUIDUtils;
import com.information.manage.basic.model.vo.DepartmentTreeVO;
import com.information.manage.common.constants.AddFileStatusEnum;
import com.information.manage.common.constants.HandleFileTypeEnum;
import com.information.manage.dao.AddFileMapper;
import com.information.manage.dao.AnalysisFileMapper;
import com.information.manage.model.dto.ClassifyStatisticDTO;
import com.information.manage.model.entity.AddFileDO;
import com.information.manage.model.entity.AnalysisFileDo;
import com.information.manage.model.query.AddAnalysisFileQuery;
import com.information.manage.model.query.AnalysisFileQuery;
import com.information.manage.model.query.AnalysisFileUpdateQuery;
import com.information.manage.model.vo.AllStatisticVO;
import com.information.manage.service.AnalysisFileService;
import com.information.manage.service.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings("all")
public class AnalysisFileServiceImpl extends ServiceImpl<AnalysisFileMapper, AnalysisFileDo> implements AnalysisFileService {

    @Value("${base.watchDirPath:/usr/local/tmp}")
    private String watchDirPath;

    @Autowired
    private FileUtils fileUtils;

    @Resource(name = "taskExecutor")
    private Executor taskExecutor;

    @Resource
    private AnalysisFileMapper analysisFileMapper;

    @Autowired
    private AddFileMapper addFileMapper;

    @Autowired
    private CommonService commonService;


    @Override
    public Result<Page<AnalysisFileDo>> queryPage(AnalysisFileQuery analysisFileQuery) {
        Page<AnalysisFileDo> analysisFileDoPage = analysisFileMapper.queryPage(new Page<>(analysisFileQuery.getCurPage(), analysisFileQuery.getPageSize())
            , analysisFileQuery.getListenFileTypeCode(), analysisFileQuery.getClassifyId(), analysisFileQuery.getTitle(), analysisFileQuery.getTransTitle()
            ,analysisFileQuery.getDeleteData(), analysisFileQuery.getPublishStartTime(), analysisFileQuery.getPublishEndTime());
        return Result.ok(analysisFileDoPage);
    }

    @Override
    public Result<List<String>> getFileEnclosurePath(Long id, Integer type) {
        AnalysisFileDo analysisFileDo = analysisFileMapper.selectById(id);
        if (analysisFileDo == null || analysisFileDo.getDeleteData() != 0) {
            return Result.fail("该数据已被删除");
        }
        String path;
        if (type == 1){
            path= analysisFileDo.getPath();
        }else if (type == 2){
            path = analysisFileDo.getSummaryPath();
        }else return Result.fail("错误的查询类型");
        if (StringUtils.isEmpty(path)) return Result.ok();
        return commonService.getVisitPath(path);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Long> add(AddAnalysisFileQuery addAnalysisFileQuery, HttpServletRequest request, List<MultipartFile> enclosures) {
        Integer userId = TokenUtils.getUserId(StringUtils.isEmpty(request.getHeader("token")) ? request.getAttribute("token").toString() : request.getHeader("token"));
        AnalysisFileDo analysisFileDo = new AnalysisFileDo();
        BeanUtils.copyProperties(addAnalysisFileQuery, analysisFileDo);
        analysisFileDo.setDeleteData(0);
        analysisFileDo.setStorageTime(new Date());
        String path = commonService.handleAddEnclosures(enclosures);
        analysisFileDo.setPath(path);  // 保存附件目录
        if (analysisFileDo.getTransTitle().length() > 80) {
            return Result.fail("译文标题不能超过80字");
        }
        if (analysisFileDo.getPath().length() > 80) {

            return Result.fail("附件路径不能超过80字");
        }
        if (analysisFileDo.getUrl().length() > 80) {
            return Result.fail("附件URL不能超过80字");
        }
        analysisFileMapper.insert(analysisFileDo);
        Long analysisFileDoId = analysisFileDo.getId();

        Date date = new Date();
        AddFileDO addFileDO = new AddFileDO();
        addFileDO.setFileName(analysisFileDo.getTitle());  // 添加的用title作为文件名称显示
        addFileDO.setType(HandleFileTypeEnum.MANU.getCode());
        addFileDO.setOperator(Long.valueOf(userId));
        addFileDO.setListenFileTypeCode(analysisFileDo.getListenFileTypeCode());
        addFileDO.setCreateTime(date);
        addFileDO.setStatus(AddFileStatusEnum.FINISH.getCode());
        addFileDO.setResult("success");
        addFileDO.setAnalysisFileId(analysisFileDoId);
        addFileDO.setUpdateTime(date);
        addFileMapper.insert(addFileDO);
        return Result.ok(analysisFileDoId);
    }

    @Override
    public Result<Boolean> updateAf(HttpServletRequest request, AnalysisFileUpdateQuery analysisFileUpdateQuery, List<MultipartFile> enclosures) {
        Long id = analysisFileUpdateQuery.getId();
        AnalysisFileDo analysisFileDo = analysisFileMapper.selectById(id);
        if (analysisFileDo == null) return Result.fail("该记录不存在");
        AnalysisFileDo upAnalysisFileDo = ConvertUtils.sourceToTargetIfNotNull(analysisFileUpdateQuery, AnalysisFileDo.class);
        if (CollectionUtils.isNotEmpty(enclosures)){
            // 需要修改时先删除原来的附件地址
            String oldPath = analysisFileDo.getPath();
            File file = new File(oldPath);
            if (file.isDirectory()) {
                boolean delete = fileUtils.deleteDir(oldPath);
                log.info("------id：{} 文件删除：{}", analysisFileDo.getId(), delete);
            }else {
                file.delete();
            }
            String path = commonService.handleAddEnclosures(enclosures);
            upAnalysisFileDo.setPath(path);
        }
        upAnalysisFileDo.setStorageUpdateTime(new Date());
        analysisFileMapper.updateById(upAnalysisFileDo);
        return Result.ok(Boolean.TRUE);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> delete(List<Long> analysisFileIds) {
        int update = analysisFileMapper.update(null, new LambdaUpdateWrapper<AnalysisFileDo>()
                .in(AnalysisFileDo::getId, analysisFileIds)
                .set(AnalysisFileDo::getDeleteData, 1));
        if (update == analysisFileIds.size()) {
            // 删除成功后需要处理删除文件
            taskExecutor.execute(() -> {
                List<AnalysisFileDo> analysisFileDos = analysisFileMapper.selectList(new LambdaQueryWrapper<AnalysisFileDo>().in(AnalysisFileDo::getId, analysisFileIds));
                Map<Long, AddFileDO> collect = addFileMapper.selectList(new LambdaQueryWrapper<AddFileDO>().in(AddFileDO::getAnalysisFileId, analysisFileIds))
                        .stream().collect(Collectors.toMap(AddFileDO::getAnalysisFileId, it -> it));
                for (AnalysisFileDo analysisFileDo : analysisFileDos) {
                    if (analysisFileDo.getDeleteData() == 1){  // 再次验证是否已删除
                        // 需要根据类型来删除
                        AddFileDO addFileDO = collect.get(analysisFileDo.getId());
                        Integer code = addFileDO.getType();
                        if (code == null) continue;
                        if (HandleFileTypeEnum.MANU.getCode() == code){  // 手动添加的仅仅删除附件即可  附件路径：  watchDirPath_addEnclosuresDir_时间年月日_uuid
                            String path = analysisFileDo.getPath();
                            boolean delete = fileUtils.deleteDir(path);
                            log.info("------id：{} 文件删除：{}", analysisFileDo.getId(), delete);
                        }else if (HandleFileTypeEnum.UPLOAD.getCode() == code || HandleFileTypeEnum.LISTEN.getCode() == code){  // 上传和监听的需要删除原文件
//                            String filePath = addFileDO.getFilePath();
                            String filePath = analysisFileDo.getPath();
                            File file = new File(filePath);
                            if (file.isDirectory()) {
                                boolean delete = fileUtils.deleteDir(filePath);
                                log.info("------id：{} 文件删除：{}", analysisFileDo.getId(), delete);
                            }else {
                                file.delete();
                            }
                        }
                    }
                }
            });
            return Result.ok(Boolean.TRUE);
        }
        throw new RuntimeException("删除失败");
    }

    @Override
    public Result<List<AllStatisticVO>> allStatistic() {
        List<DepartmentTreeVO> departmentTreeVOS = commonService.getDepartmentTreeVOList();
        if (CollectionUtils.isEmpty(departmentTreeVOS)) return Result.fail("暂不存在任何统计信息");

        Map<Long, ClassifyStatisticDTO> collect = analysisFileMapper.classifyStatistic().stream().collect(Collectors.toMap(ClassifyStatisticDTO::getClassifyId, v -> v));
        List<AllStatisticVO> list = commonService.recursionStatistic(departmentTreeVOS, collect);

        // 可能存在某些分类id在departmentTreeVOS中不存在，即可能某些分类id已经被删除，此时全部当作其他
        Set<Long> allIds = commonService.getAllIds(departmentTreeVOS);
        Set<Long> keySet = collect.keySet();
        keySet.removeAll(allIds);
        if (CollectionUtils.isNotEmpty(keySet)) {
            AllStatisticVO allStatisticVO = new AllStatisticVO();
            allStatisticVO.setName("其它");
            Long otherCount = 0L;
            for (Long aLong : keySet) {
                ClassifyStatisticDTO classifyStatisticDTO = collect.get(aLong);
                Long totalCount = classifyStatisticDTO.getTotalCount();
                otherCount += totalCount;
            }
            allStatisticVO.setAll(otherCount);
            list.add(allStatisticVO);
        }

        // 添加全部
        AllStatisticVO allStatisticVO = new AllStatisticVO();
        allStatisticVO.setName("文章总数");
        allStatisticVO.setAll(list.stream().mapToLong(AllStatisticVO::getAll).sum());
        list.add(allStatisticVO);
        return Result.ok(list);
    }


}
